﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace hmi
{
    class UdpComm:ICommunication
    {
        public Socket LocalSocket { get; set; }//Socket若要重新绑定，需先Close，一旦Close，就会释放资源，因此每次重新绑定前都需重新new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)

        public static int RECEIVE_SIZE = 1024;

        private byte[] receiveBuffer = new byte[RECEIVE_SIZE];

        private EndPoint targetEndPoint;

        public IPEndPoint LocalIPEndPoint { get; set; }
        public IPEndPoint TargetIPEndPoint { get; set; }

        public bool IsCommRight { get; set; }

        public UdpComm()
        {
            InitPara();
        }

        private void InitPara()
        {
            IsCommRight = true;

            IPAddress localIP = IPAddress.Any;
            IPAddress targetIP = IPAddress.Parse(ConfigurationManager.AppSettings["TargetIP"]);
            int targetPort = Convert.ToInt32(ConfigurationManager.AppSettings["TargetPort"]);
            TargetIPEndPoint = new IPEndPoint(targetIP, targetPort);

            string name = Dns.GetHostName();
            IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
            List<string> localIPV4List = new List<string>();
            foreach (IPAddress ipa in ipadrlist)
            {
                if (ipa.AddressFamily == AddressFamily.InterNetwork)
                {
                    var ipStr = ipa.ToString();                    
                    localIPV4List.Add(ipStr);
                }
            }
            if (localIPV4List.Count > 0)
            {
                string localIPStr = ConfigurationManager.AppSettings["LocalIP"];
                if (localIPStr == "" || !localIPV4List.Contains(localIPStr))
                {
                    localIP = IPAddress.Parse(localIPV4List[0]); //没有IP存储值或者当前可选IP中未包含存储值,默认选取可选的第一个IP                 
                }
                else
                {
                    localIP = IPAddress.Parse(localIPStr);
                }
            }
            else//未检测到网络，打开网络时会弹出提示窗口，此处不处理
            {
                return;
            }
            //IPAddress localIP = IPAddress.Parse(ConfigurationManager.AppSettings["LocalIP"]);
            int localPort = Convert.ToInt32(ConfigurationManager.AppSettings["LocalPort"]);
            LocalIPEndPoint = new IPEndPoint(localIP, localPort);
        }

        public bool IsOpen
        {
            get
            {
                if (LocalSocket == null)
                {
                    return false;
                }
                return LocalSocket.IsBound;
            }
        }

        public void Open()
        {            
            Close();
            LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            try
            {
                LocalSocket.Bind(LocalIPEndPoint);//此处如果绑定失败，需要相应处理
            }
            catch
            {
                IsCommRight = false;
                return;
            }            
            ListenReceiveData();
            IsCommRight = true;
        }

        public void Close()
        {
            if (LocalSocket == null)
            {
                return;
            }
            if (LocalSocket.IsBound)
            {
                LocalSocket.Close();
            }
            LocalSocket = null;//LocalSocket.Close()之后，在LocalSocket重新赋值前，LocalSocket并不会释放，因此手动赋值为null
        }

        public void SendByteData(byte[] byteData)
        {
            if (!IsOpen)
            {
                return;
            }
            try
            {
                LocalSocket.BeginSendTo(byteData, 0, byteData.Length, SocketFlags.None, TargetIPEndPoint,
                            (IAsyncResult ar) => { }, LocalSocket);
            }
            catch
            {
                //MessageBox.Show("失败");
            }
        }

        public void ListenReceiveData()
        {
            try
            {
                IPEndPoint targetIPEndPointnder = new IPEndPoint(IPAddress.Any, 0);
                targetEndPoint = (EndPoint)targetIPEndPointnder;
                LocalSocket.BeginReceiveFrom(receiveBuffer, 0,
                                        receiveBuffer.Length,
                                        SocketFlags.None,
                                        ref targetEndPoint,
                                        new AsyncCallback(ReceiveData),
                                        targetEndPoint);
            }
            catch
            {
                //MessageBox.Show("UDP连接创建失败");
            }
        }

        private void ReceiveData(IAsyncResult asyncResult)
        {
            int recv_len;
            try
            {
                recv_len = LocalSocket.EndReceiveFrom(asyncResult, ref targetEndPoint);
            }
            catch
            {
                //MessageBox.Show("断开连接");
                return;
            }

            byte[] readBuffer = new byte[recv_len];
            Array.Copy(receiveBuffer, 0, readBuffer, 0, recv_len);
            LocalSocket.BeginReceiveFrom(receiveBuffer, 0,
                                    receiveBuffer.Length,
                                    SocketFlags.None,
                                    ref targetEndPoint,
                                    new AsyncCallback(ReceiveData),
                                    targetEndPoint);

            Protocol.Instance.ExtractData(readBuffer);//提取有用的数据
            CommManage.Instance.ReceiveBytesDebug(readBuffer);//收到的原始数据交由调试界面显示
        }
    }
}
